/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { TypeNode, SyntaxKind, UnionTypeNode } from 'ts-morph';
import { PropertyKind, TypeStructure, SerializerMetadata, TypeDependency } from '../Types';
import { ITypeHandler, TypeContext, ConversionDirection } from './ITypeHandler';
import { BaseTypeHandler } from './BaseTypeHandler';
import { CustomError, ErrorCodes } from '../utils/CustomError';

type UnionPattern = 'optional' | 'nullable' | 'union' | 'optionalNullable';

abstract class UnionTypeHandler extends BaseTypeHandler implements ITypeHandler {
  abstract readonly name: string;
  abstract readonly kind: PropertyKind;
  abstract readonly priority: number;

  /**
   * 子类指定支持的联合类型模式
   */
  protected abstract readonly supportedPattern: UnionPattern;

  // ==================== 阶段1: 类型识别 ====================

  matches(typeNode: TypeNode): boolean {
    // 必须是UnionType
    if (typeNode.getKind() !== SyntaxKind.UnionType) {
      return false;
    }

    const unionType = typeNode as UnionTypeNode;
    const memberTypes = unionType.getTypeNodes();

    // 辅助函数：检查是否为 null 类型节点
    const isNullType = (t: TypeNode): boolean => {
      return t.getKind() === SyntaxKind.LiteralType && t.getText() === 'null';
    };

    // 辅助函数：检查是否为 undefined 类型节点
    const isUndefinedType = (t: TypeNode): boolean => {
      return t.getKind() === SyntaxKind.UndefinedKeyword;
    };

    // 根据supportedPattern匹配不同的联合类型模式
    switch (this.supportedPattern) {
      case 'optional':
        // T | undefined （必须是2个成员，其中一个是undefined，另一个不是null）
        if (memberTypes.length !== 2) {
          return false;
        }
        const hasUndefined = memberTypes.some(isUndefinedType);
        const hasNull = memberTypes.some(isNullType);
        // 确保有undefined，但另一个成员不是null
        return hasUndefined && !hasNull;

      case 'nullable':
        // T | null （必须是2个成员，其中一个是null，另一个不是undefined）
        if (memberTypes.length !== 2) {
          return false;
        }
        const hasNullable = memberTypes.some(isNullType);
        const hasUndefinedNullable = memberTypes.some(isUndefinedType);
        // 确保有null，但另一个成员不是undefined
        return hasNullable && !hasUndefinedNullable;

      case 'optionalNullable':
        // T | null | undefined （必须是3个成员，包含null和undefined，还有一个其他类型）
        return memberTypes.length === 3 &&
          memberTypes.some(isNullType) &&
          memberTypes.some(isUndefinedType);

      case 'union':
        // 普通联合类型（其他所有联合类型）
        return true;

      default:
        return false;
    }
  }

  // ==================== 阶段2: 类型解析 ====================

  parse(typeNode: TypeNode, context: TypeContext): TypeStructure {
    const unionType = typeNode as UnionTypeNode;

    // 统一解析所有成员类型
    const members = this.parseUnionMembers(unionType, context);

    // 收集所有依赖
    const allDependencies: TypeDependency[] = [];
    let maxDepth = 0;
    members.forEach(member => {
      allDependencies.push(...member.dependencies);
      maxDepth = Math.max(maxDepth, member.depth);
    });

    return {
      kind: this.kind,
      depth: this.supportedPattern === 'union' ? 0 : maxDepth + 1,
      sourceText: typeNode.getText(),
      args: [],
      dependencies: allDependencies,
      unionDetails: members
    };
  }

  // ==================== 阶段3: 序列化器配置 ====================

  getSerializerMetadata(structure: TypeStructure, withParam?: string): SerializerMetadata {
    const serializerName = this.getSerializerName();
    const defaultInstantiation = this.generateInstantiation(structure);

    return {
      name: serializerName,
      typeDeclaration: this.generateTypeDeclaration(structure),
      instantiationTemplate: this.applyWithParam(withParam, defaultInstantiation, structure),
      encodeMethod: 'encodeSerializableElement',
      decodeMethod: 'deserialize',
      decoderType: `${structure.sourceText} | undefined`,
      needsTypeAssertion: false
    };
  }

  // ==================== 阶段4: 代码生成 ====================

  generateInstantiation(structure: TypeStructure): string {
    if (!structure.unionDetails || structure.unionDetails.length === 0) {
      throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
    }

    const serializerName = this.getSerializerName();

    // 处理Optional/Nullable/OptionalNullable模式
    if (this.isOptionalOrNullablePattern()) {
      return this.generateOptionalNullableInstantiation(structure);
    }

    // Union: 所有成员类型
    const primitiveTypes = ['undefined', 'null', 'boolean', 'number', 'string', 'bigint'];
    const unionTypes = structure.unionDetails.map(member => {
      return primitiveTypes.includes(member.sourceText)
        ? `'${member.sourceText}'`
        : member.sourceText;
    }).join(', ');

    const typeDeclaration = structure.unionDetails.map(member => member.sourceText).join(' | ');
    return `new ${serializerName}<${typeDeclaration}>([${unionTypes}])`;
  }

  generateTypeDeclaration(structure: TypeStructure): string {
    if (!structure.unionDetails || structure.unionDetails.length === 0) {
      throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
    }

    const serializerName = this.getSerializerName();

    // 处理Optional/Nullable/OptionalNullable模式
    if (this.isOptionalOrNullablePattern()) {
      const innerMember = this.getInnerMember(structure);
      if (!innerMember) {
        throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
      }

      return `${serializerName}<${innerMember.sourceText}>`;
    }

    // Union: 所有成员类型
    const typeDeclaration = structure.unionDetails.map(member => member.sourceText).join(' | ');
    return `${serializerName}<${typeDeclaration}>`;
  }

  generateTypeKey(structure: TypeStructure): string {
    if (!structure.unionDetails || structure.unionDetails.length === 0) {
      throw new CustomError(`${this.name}: missing unionDetails`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
    }

    // 处理Optional/Nullable/OptionalNullable模式
    if (this.isOptionalOrNullablePattern()) {
      return this.generateOptionalNullableTypeKey(structure);
    }

    // Union: 所有成员typeKey的数组
    const memberTypeKeys = structure.unionDetails.map(member => {
      const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
      const handler = TypeHandlerRegistry.getInstance().getHandlerForKind(member.kind);
      return handler.generateTypeKey(member);
    });

    return `[${memberTypeKeys.join(', ')}]`;
  }

  // ==================== Protected 工具方法 ====================

  /**
   * 检查是否为Optional、Nullable或OptionalNullable模式
   */
  protected isOptionalOrNullablePattern(): boolean {
    return this.supportedPattern === 'optional' || 
           this.supportedPattern === 'nullable' || 
           this.supportedPattern === 'optionalNullable';
  }

  /**
   * 获取Optional/Nullable/OptionalNullable模式的内部成员类型
   */
  protected getInnerMember(structure: TypeStructure): TypeStructure | undefined {
    switch (this.supportedPattern) {
      case 'optional':
        return structure.unionDetails?.find(m => m.kind !== PropertyKind.UNDEFINED);
      case 'nullable':
        return structure.unionDetails?.find(m => m.kind !== PropertyKind.NULL);
      case 'optionalNullable':
        return structure.unionDetails?.find(m => 
          m.kind !== PropertyKind.NULL && m.kind !== PropertyKind.UNDEFINED
        );
      default:
        return undefined;
    }
  }

  /**
   * 生成Optional/Nullable/OptionalNullable模式的实例化代码
   */
  protected generateOptionalNullableInstantiation(structure: TypeStructure): string {
    if (this.supportedPattern === 'optionalNullable' && structure.unionDetails?.length !== 3) {
      throw new CustomError(`${this.name}: expected 3 union members`, ErrorCodes.UNION_EXPEDTED_THREE);
    }
    
    if (this.supportedPattern !== 'optionalNullable' && structure.unionDetails?.length !== 2) {
      throw new CustomError(`${this.name}: expected 2 union members`, ErrorCodes.UNION_EXPEDTED_TWO);
    }

    const innerMember = this.getInnerMember(structure);
    if (!innerMember) {
      throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
    }

    const innerType = innerMember.sourceText;
    const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
    const innerHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(innerMember.kind);

    const innerSerializer = innerHandler.generateInstantiation(innerMember);
    const serializerName = this.getSerializerName();
    return `new ${serializerName}<${innerType}>(${innerSerializer})`;
  }

  /**
   * 生成Optional/Nullable/OptionalNullable模式的类型键
   */
  protected generateOptionalNullableTypeKey(structure: TypeStructure): string {
    const innerMember = this.getInnerMember(structure);
    if (!innerMember) {
      throw new CustomError(`${this.name}: cannot find inner member`, ErrorCodes.UNION_INNER_NOT_FOUND);
    }

    const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
    const innerHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(innerMember.kind);
    const innerTypeKey = innerHandler.generateTypeKey(innerMember);
    
    switch (this.supportedPattern) {
      case 'optional':
        return `[${innerTypeKey}, "'undefined'"]`;
      case 'nullable':
        return `[${innerTypeKey}, "'null'"]`;
      case 'optionalNullable':
        return `[${innerTypeKey}, "'null'", "'undefined'"]`;
      default:
        throw new CustomError(`${this.name}: unsupported pattern`, ErrorCodes.UNION_UNSUPPORTED_PATTERN);
    }
  }

  /**
   * 解析联合类型的所有成员
   */
  protected parseUnionMembers(typeNode: UnionTypeNode, context: TypeContext): TypeStructure[] {
    const memberTypes = typeNode.getTypeNodes();
    const members: TypeStructure[] = [];

    for (const memberType of memberTypes) {
      const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
      const memberStructure = TypeHandlerRegistry.getInstance().parseType(memberType, {
        ...context,
        depth: context.depth + 1
      });
      members.push(memberStructure);
    }

    return members;
  }

  // ==================== Sendable转换 ====================

  generateSendableTypeDeclaration(structure: TypeStructure): string {
    if (!structure.unionDetails || structure.unionDetails.length === 0) {
      throw new CustomError(`${this.name}: missing unionDetails for Sendable type declaration`, ErrorCodes.UNION_STRUCTURE_NOT_FOUND);
    }

    // 递归获取TypeHandlerRegistry
    const registry = require('./TypeHandlerRegistry').TypeHandlerRegistry.getInstance();

    // 递归转换每个成员类型为Sendable类型
    const sendableMemberTypes = structure.unionDetails.map(member => {
      const handler = registry.getHandlerForKind(member.kind);
      if (!handler) {
        throw new CustomError(`${this.name}: no handler for member type: ${member.kind}`, ErrorCodes.HANDLER_NOT_FOUND);
      }
      return handler.generateSendableTypeDeclaration(member);
    });

    // 联合所有Sendable成员类型
    return sendableMemberTypes.join(' | ');
  }

  generatePropertyConversion(structure: TypeStructure, sourceValue: string, direction: ConversionDirection): string {
    // 联合类型的转换无法在编译时确定具体类型，直接传递
    // 实际转换由运行时的具体类型决定
    // 注意：这可能需要在运行时检查类型并调用相应的转换方法
    return sourceValue;
  }
}

class NullableHandler extends UnionTypeHandler {
  readonly name = 'NullableHandler';
  readonly kind = PropertyKind.NULLABLE;
  readonly priority = 95; // 高于普通UnionHandler
  protected readonly supportedPattern = 'nullable' as const;

  protected getSerializerName(): string {
    return 'NullableSerializer';
  }
}

class OptionalHandler extends UnionTypeHandler {
  readonly name = 'OptionalHandler';
  readonly kind = PropertyKind.OPTIONAL;
  readonly priority = 95; // 高于普通UnionHandler
  protected readonly supportedPattern = 'optional' as const;

  protected getSerializerName(): string {
    return 'OptionalSerializer';
  }
}

class OptionalNullableHandler extends UnionTypeHandler {
  readonly name = 'OptionalNullableHandler';
  readonly kind = PropertyKind.OPTIONAL_NULLABLE;
  readonly priority = 95; // 高于普通UnionHandler
  protected readonly supportedPattern = 'optionalNullable' as const;

  protected getSerializerName(): string {
    return 'OptionalNullableSerializer';
  }
}

class UnionHandler extends UnionTypeHandler {
  readonly name = 'UnionHandler';
  readonly kind = PropertyKind.UNION;
  readonly priority = 85; // 低于Optional和Nullable，作为fallback
  protected readonly supportedPattern = 'union' as const;

  protected getSerializerName(): string {
    return 'UnionTypeSerializer';
  }
}

/**
 * 工厂函数：创建所有联合类型Handler
 * @returns 4个联合类型Handler实例
 *
 * 优先级顺序（从高到低）：
 * 1. OptionalHandler (95) - T | undefined (T不为null)
 * 2. NullableHandler (95) - T | null (T不为undefined)
 * 3. OptionalNullableHandler (95) - T | null | undefined (T为其他类型)
 * 4. UnionHandler (85) - 其他所有联合类型 (包括 null | undefined)
 *
 * 特殊情况说明：
 * - `null | undefined` 会被 UnionHandler 处理，生成 UnionTypeSerializer<null | undefined>
 * - `T | undefined` (T非null) 会被 OptionalHandler 处理，生成 OptionalSerializer<T>
 * - `T | null` (T非undefined) 会被 NullableHandler 处理，生成 NullableSerializer<T>
 * - `T | null | undefined` 会被 OptionalNullableHandler 处理，生成 OptionalNullableSerializer<T>
 */
export function createUnionTypeHandlers(): ITypeHandler[] {
  return [
    new OptionalHandler(),
    new NullableHandler(),
    new OptionalNullableHandler(),
    new UnionHandler()
  ];
}
